#pragma once
#include "DJoint.h"

namespace Skill
{
	namespace Ode
	{
		ref class DWorld;
		ref class DVector3;
		namespace Joints
		{
			ref class DJointGroup;
			public ref class DPiston : DJoint
			{	
			protected:
				virtual void CollectManagedMemory() override;
			public:
				
				///<summary>
				/// Create a new joint of Piston type.
				///</summary>
				///<param name = "world"> Wrold </param>
				///<param name = "group">
				/// set to null to allocate the joint normally.
				/// If it is valid the joint is allocated in the given joint group.
				///</param>
				DPiston(DWorld^ world , DJointGroup^ group);

				///<summary>
				/// Gets or set the joint anchor
				///
				/// This returns the point on body 1. If the joint is perfectly satisfied,
				/// this will be the same as the point on body 2 in direction perpendicular
				/// to the prismatic axis.
				///</summary>
				REF_PROP_DECLARATION_GETSET(DVector3,Anchor1);

				///<summary>
				/// Set the Piston anchor as if the 2 bodies were already at [dx,dy, dz] appart.				
				///
				/// This function initialize the anchor and the relative position of each body
				/// as if the position between body1 and body2 was already the projection of [dx, dy, dz]
				/// along the Piston axis. (i.e as if the body1 was at its current position - [dx,dy,dy] when the
				/// axis is set).
				///</summary>
				///<example>				
				/// float offset = 3;
				/// DVector3 axis = piston.Axis;				
				/// piston.Anchor = new DVector3(0, 0, 0);
				///  //If you request the position you will have: piston.Position == 0
				/// Piston.SetAnchorOffset(0, 0, 0, axis.X * offset, axis.Y * offset, axis.Z * offset);
				///  //If you request the position you will have: Piston.Position == offset
				///</example>
				///<param name = "x"> The X position of the anchor point in world frame </param>
				///<param name = "y"> The Y position of the anchor point in world frame</param>
				///<param name = "z"> The Z position of the anchor point in world frame</param>
				///<param name = "dx"> 
				/// A delta to be substracted to the X position as if the anchor was set
				/// when body1 was at current_position.X - dx</param>
				///<param name = "dy"> 
				/// A delta to be substracted to the Y position as if the anchor was set
				/// when body1 was at current_position.Y - dy</param>
				///<param name = "dz"> 
				/// A delta to be substracted to the Z position as if the anchor was set
				/// when body1 was at current_position.Z - dz</param>								
				void SetAnchorOffset(dReal x, dReal y, dReal z, dReal dx, dReal dy, dReal dz);

				void SetAnchorOffset(DVector3^ p, DVector3^ d);
				
				///<summary>
				/// Gets or set the prismatic axis (This is also the rotoide axis.
				///</summary>
				REF_PROP_DECLARATION_GETSET(DVector3,Axis);				

				///<summary>
				/// set joint parameter
				///</summary>
				void SetParam(DJointParameters parameter, dReal value);	

				///<summary>
				/// Get joint parameter
				///</summary>
				dReal GetParam(DJointParameters parameter);	

				///<summary>
				/// Applies the given force in the slider's direction.
				///
				/// That is, it applies a force with specified magnitude, in the direction of
				/// prismatic's axis, to body1, and with the same magnitude but opposite
				/// direction to body2.  This function is just a wrapper for dBodyAddForce().
				///</summary>
				void AddForce(dReal force);

				///<summary>
				/// Get the Piston linear position (i.e. the piston's extension)
				///
				/// When the axis is set, the current position of the attached bodies is
				/// examined and that position will be the zero position.
				///</summary>
				VALUE_PROP_DECLARATION_GET(dReal,Position);

				///<summary>
				/// Get the piston linear position's time derivative.
				///</summary>
				VALUE_PROP_DECLARATION_GET(dReal,PositionRate);
				
				///<summary>
				/// Get the Piston angular position (i.e. the  twist between the 2 bodies)
				///
				/// When the axis is set, the current position of the attached bodies is
				/// examined and that position will be the zero position.
				///</summary>
				VALUE_PROP_DECLARATION_GET(dReal,Angle);

				///<summary>
				/// Get the piston angular position's time derivative.
				///</summary>
				VALUE_PROP_DECLARATION_GET(dReal,AngleRate);				

				///<summary>
				/// Get the joint anchor w.r.t. body 2
				///
				/// This returns the point on body 2. You can think of a Piston
				/// joint as trying to keep the result of dJointGetPistonAnchor() and
				/// dJointGetPistonAnchor2() the same in the direction perpendicular to the
				/// pirsmatic axis. If the joint is perfectly satisfied,
				/// this function will return the same value as dJointGetPistonAnchor() to
				/// within roundoff errors. dJointGetPistonAnchor2() can be used, along with
				/// dJointGetPistonAnchor(), to see how far the joint has come apart.
				///</summary>
				REF_PROP_DECLARATION_GET(DVector3,Anchor2);				
			};
		}
	}
}